package com.uxsino.commons.utils.config;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class PropXMLDocument implements PropDocument {
    private static Logger logger = LoggerFactory.getLogger(PropXMLDocument.class);

    private final Document doc;

    public enum SOURCE_TYPE {
                             EXTERNAL_FILE,
                             STRING
    };

    public PropXMLDocument(String src, String sourceName, SOURCE_TYPE sourceType) {
        switch (sourceType) {
        case EXTERNAL_FILE:
            File f = new File(src);
            doc = PositionalXMLReader.getNormalizedDocumentFromFile(f, sourceName);
            break;
        case STRING:
        default: // got a warning about "final" field is not set without default
            doc = PositionalXMLReader.getNormalizedDocumentFromString(src, sourceName);

        }
        if (doc == null) {
            throw new IllegalArgumentException("xml source not valid for " + sourceName);
        }
    }

    public PropXMLDocument(File f, String sourceName) {
        doc = PositionalXMLReader.getNormalizedDocumentFromFile(f, sourceName);
    }

    public PropXMLDocument(InputStream is, String sourceName) {

        doc = PositionalXMLReader.getNormalizedDocumentFromStream(is, sourceName);
    }

    @Override
    public String getSourceName() {
        return (String) doc.getUserData("src");
    }

    @Override
    public String getProp(String name) {
        return doc.getDocumentElement().getAttribute(name);
    }

    @Override
    public List<PropElement> getElements(String name) {
        List<PropElement> elements = new ArrayList<>();
        if (doc == null)
            return elements;
        try {
            NodeList nl = doc.getDocumentElement().getElementsByTagName(name);

            for (int i = 0; i < nl.getLength(); i++) {
                elements.add(new PropXMLElement(this, (Element) nl.item(i)));
            }
        } catch (Exception e) {
            logger.error(" error to get element: " + name + " from doc" + doc, e);
        }
        return elements;
    }

    @Override
    public List<PropElement> getElements() {
        NodeList nl = doc.getDocumentElement().getChildNodes();
        List<PropElement> elements = new ArrayList<>();

        for (int i = 0; i < nl.getLength(); i++) {
            elements.add(new PropXMLElement(this, (Element) nl.item(i)));
        }
        return elements;
    }

    @Override
    public PropElement getFirstElement(String name, String fieldAsTagName) {
        if (doc == null)
            return null;
        try {
            NodeList nl = doc.getDocumentElement().getElementsByTagName(name);
            if (nl.getLength() > 0)
                return new PropXMLElement(this, (Element) nl.item(0));

        } catch (Exception e) {
            logger.error(" error to get element: " + name + " from doc" + doc, e);
        }
        return null;
    }

    public PropElement getRootElement() {
        return new PropXMLElement(this, doc.getDocumentElement());
    }

    public boolean isValid() {
        return doc != null;
    }
}
